package cn.qmso.wxPay.v2;

import cn.qmso.wxPay.v2.base.PayV2;
import cn.qmso.wxPay.v2.base.WxPayUtil;
import cn.qmso.wxPay.v2.base.WxPayV2Content;
import cn.qmso.wxPay.v2.config.WxPayV2Config;
import cn.qmso.wxPay.v2.paramEntity.Receivers;
import cn.qmso.wxPay.v2.paramEntity.SeparateAccountParam;
import cn.qmso.wxPay.v2.paramEntity.AddSeparateAccountParam;
import cn.qmso.wxPay.v2.paramEntity.DeleteSeparateAccountParam;
import cn.qmso.wxPay.v2.paramEntity.DeleteReceiver;
import cn.qmso.wxPay.v2.paramEntity.ReturnSeparateAccountParam;
import cn.qmso.wxPay.v2.paramEntity.SelectSeparateAccountParam;
import cn.qmso.wxPay.v2.paramEntity.SelectFallBackResultSeparateAccountParam;
import cn.qmso.wxPay.v2.paramEntity.SuccessSeparateAccountParam;
import cn.qmso.wxPay.v2.paramEntity.SelectNotSeparateAccountParam;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;


/**
 * @author lijuntao
 * 微信分账v2
 */
@Component
public class WxSeparateAccount extends PayV2 {


    @Autowired
    private WxPayV2Config defaultWxPayV2Config;

    /**
     * 请求分账（单次分账，多次分账）
     * 单次分账请求按照传入的分账接收方账号和资金进行分账，同时会将订单剩余的待分账金额解冻给本商户。故操作成功后，订单不能再进行分账，也不能进行分账完结。
     * ● 微信订单支付成功后，商户发起分账请求，将结算后的钱分到分账接收方。多次分账请求仅会按照传入的分账接收方进行分账，不会对剩余的金额进行任何操作。故操作成功后，在待分账金额不等于零时，订单依旧能够再次进行分账。
     * ● 多次分账，可以将本商户作为分账接收方直接传入，实现释放资金给本商户的功能
     * ● 对同一笔订单最多能发起20次多次分账请求
     * @param separateAccountParam 请求参数实体
     * @param receivers         请求参数实体集合
     * @return 请求结果
     * @throws Exception 异常
     */
    public Map<String, String> separateAccount(SeparateAccountParam separateAccountParam, List<Receivers> receivers) throws Exception {
        return separateAccount(separateAccountParam, receivers, defaultWxPayV2Config);
    }

    public Map<String, String> separateAccount(SeparateAccountParam separateAccountParam, List<Receivers> receivers, WxPayV2Config wxPayV2Config) throws Exception {
        Map<String, String> map = WxPayUtil.objectToMap(separateAccountParam);
        map.put("receivers", JSONObject.toJSONString(receivers));
        String signedXml = generateSignedXml(map, wxPayV2Config);
        return carryCertificateRequestPost(wxPayV2Config, WxPayV2Content.DIVIDE_ACCOUNTS, signedXml);
    }


    /**
     * 添加分账用户
     * 商户发起添加分账接收方请求，后续可通过发起分账请求将结算后的钱分到该分账接收方。
     *
     * @param addSeparateAccountParam 请求参数
     * @param receiver             请求参数
     * @return 请求结果
     * @throws Exception 异常
     */
    public Map<String, String> addSeparateAccount(AddSeparateAccountParam addSeparateAccountParam, DeleteReceiver receiver) throws Exception {
        return addSeparateAccount(addSeparateAccountParam,receiver,defaultWxPayV2Config);
    }

    public Map<String, String> addSeparateAccount(AddSeparateAccountParam addSeparateAccountParam, DeleteReceiver receiver, WxPayV2Config wxPayV2Config) throws Exception {
        Map<String, String> map = WxPayUtil.objectToMap(addSeparateAccountParam);
        map.put("receiver", JSONObject.toJSONString(receiver));
        String signedXml = generateSignedXml(map,wxPayV2Config);
        return notCarryCertificateRequestPost(addSeparateAccountParam.getMch_id(), WxPayV2Content.ADD_RECEIVER, signedXml);
    }


    /**
     * 删除分账用户
     * 商户发起删除分账接收方请求，删除后不支持将结算后的钱分到该分账接收方。
     *
     * @param deleteSeparateAccountParam 请求参数实体
     * @param receiver                请求参数实体
     * @return 请求结果
     * @throws Exception 欧昌
     */
    public Map<String, String> deleteSeparateAccount(DeleteSeparateAccountParam deleteSeparateAccountParam, DeleteReceiver receiver) throws Exception {
        return deleteSeparateAccount(deleteSeparateAccountParam,receiver,defaultWxPayV2Config);
    }


    public Map<String, String> deleteSeparateAccount(DeleteSeparateAccountParam deleteSeparateAccountParam, DeleteReceiver receiver, WxPayV2Config wxPayV2Config) throws Exception {
        Map<String, String> map = WxPayUtil.objectToMap(deleteSeparateAccountParam);
        map.put("receiver", JSONObject.toJSONString(receiver));
        String signedXml = generateSignedXml(map,wxPayV2Config);
        return notCarryCertificateRequestPost(deleteSeparateAccountParam.getMch_id(), WxPayV2Content.DELETE_RECEIVER, signedXml);
    }


    /**
     * 查询分账结果
     * 发起分账请求后，可调用此接口查询分账结果；发起分账完结请求后，可调用此接口查询分账完结的执行结果。
     *
     * @param selectSeparateAccountParam 请求参数实体
     * @return 请求结果
     * @throws Exception 异常
     */
    public Map<String, String> selectSeparateAccount(SelectSeparateAccountParam selectSeparateAccountParam) throws Exception {
        return selectSeparateAccount(selectSeparateAccountParam,defaultWxPayV2Config);
    }

    public static Map<String, String> selectSeparateAccount(SelectSeparateAccountParam selectSeparateAccountBo, WxPayV2Config wxPayV2Config) throws Exception {
        Map<String, String> map = WxPayUtil.objectToMap(selectSeparateAccountBo);
        String signedXml = generateSignedXml(map, wxPayV2Config);
        return notCarryCertificateRequestPost(selectSeparateAccountBo.getMch_id(), WxPayV2Content.QUERY_DIVIDE_ACCOUNTS, signedXml);
    }


    /**
     * 完结分账
     * 1、不需要进行分账的订单，可直接调用本接口将订单的金额全部解冻给本商户
     * 2、调用多次分账接口后，需要解冻剩余资金时，调用本接口将剩余的分账金额全部解冻给特约商户
     * 3、已调用请求单次分账后，剩余待分账金额为零，不需要再调用此接口。
     *
     * @param successSeparateAccountParam 请求参数实体
     * @return 请求结果
     * @throws Exception 异常
     */
    public Map<String, String> successSeparateAccount(SuccessSeparateAccountParam successSeparateAccountParam) throws Exception {
        return successSeparateAccount(successSeparateAccountParam,defaultWxPayV2Config);
    }

    public Map<String, String> successSeparateAccount(SuccessSeparateAccountParam successSeparateAccountParam, WxPayV2Config wxPayV2Config) throws Exception {
        Map<String, String> map = WxPayUtil.objectToMap(successSeparateAccountParam);
        String signedXml = generateSignedXml(map, wxPayV2Config);
        return carryCertificateRequestPost(wxPayV2Config, WxPayV2Content.SUCCESS_SEPARATE_ACCOUNT, signedXml);
    }


    /**
     * 查询订单待分账金额
     * 商户可通过调用此接口查询订单剩余待分金额。
     *
     * @param selectNotSeparateAccountParam 参数实体
     * @return 请求结果
     * @throws Exception 异常
     */
    public Map<String, String> selectNotSeparateAccount(SelectNotSeparateAccountParam selectNotSeparateAccountParam) throws Exception {
        return selectNotSeparateAccount(selectNotSeparateAccountParam,defaultWxPayV2Config);
    }

    public Map<String, String> selectNotSeparateAccount(SelectNotSeparateAccountParam selectNotSeparateAccountParam, WxPayV2Config wxPayV2Config) throws Exception {
        Map<String, String> map = WxPayUtil.objectToMap(selectNotSeparateAccountParam);
        String signedXml = generateSignedXml(map, wxPayV2Config);
        return notCarryCertificateRequestPost(selectNotSeparateAccountParam.getMch_id(), WxPayV2Content.SELECT_NOT_SEPARATE_ACCOUNT, signedXml);
    }

    /**
     * 分账退回
     * ● 对订单进行退款时，如果订单已经分账，可以先调用此接口将指定的金额从分账接收方（仅限商户类型的分账接收方）回退给本商户，然后再退款。
     * ● 回退以原分账请求为依据，可以对分给分账接收方的金额进行多次回退，只要满足累计回退不超过该请求中分给接收方的金额。
     * ● 此接口采用同步处理模式，即在接收到商户请求后，会实时返回处理结果
     * ● 此功能需要接收方在商户平台-交易中心-分账-分账接收设置下，开启同意分账回退后，才能使用。
     *
     * @param returnSeparateAccountBo 参数实体
     * @return 请求内容
     * @throws Exception 异常
     */
    public Map<String, String> returnSeparateAccount(ReturnSeparateAccountParam returnSeparateAccountBo) throws Exception {
        return returnSeparateAccount(returnSeparateAccountBo,defaultWxPayV2Config);
    }

    public Map<String, String> returnSeparateAccount(ReturnSeparateAccountParam returnSeparateAccountBo, WxPayV2Config wxPayV2Config) throws Exception {
        Map<String, String> map = WxPayUtil.objectToMap(returnSeparateAccountBo);
        String signedXml = generateSignedXml(map, wxPayV2Config);
        return carryCertificateRequestPost(wxPayV2Config, WxPayV2Content.RETURN_SEPARATE_ACCOUNT, signedXml);
    }

    /**
     * 回退结果查询
     * ● 商户需要核实回退结果，可调用此接口查询回退结果。
     * ● 如果分账回退接口返回状态为处理中，可调用此接口查询回退结果
     *
     * @param selectFallBackResultSeparateAccountParam 请求参数
     * @return 请求结果
     * @throws Exception 异常
     */
    public Map<String, String> selectFallBackResultSeparateAccount(SelectFallBackResultSeparateAccountParam selectFallBackResultSeparateAccountParam) throws Exception {
        return selectFallBackResultSeparateAccount(selectFallBackResultSeparateAccountParam,defaultWxPayV2Config);
    }

    public Map<String, String> selectFallBackResultSeparateAccount(SelectFallBackResultSeparateAccountParam selectFallBackResultSeparateAccountParam, WxPayV2Config wxPayV2Config) throws Exception {
        Map<String, String> map = WxPayUtil.objectToMap(selectFallBackResultSeparateAccountParam);
        String signedXml = generateSignedXml(map, wxPayV2Config);
        return notCarryCertificateRequestPost(wxPayV2Config.getMchId(), WxPayV2Content.SELECT_FALL_BACK_RESULT_SEPARATE_ACCOUNT, signedXml);
    }
}